﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Epsilon.Expr
{
    public class RecordExpr : Expression
    {
        public string Name { get; private set; }

        public RecordExpr(string name, int l, int c)
            : base(l, c)
        {
            Name = name;
        }
    }

    public class RecModExpr : Expression
    {
        public Expression Record { get; private set; }
        public string Name { get; private set; }
        public List<RecordField> Modifications { get; private set; }

        public RecModExpr(Expression record, string name, List<RecordField> mods, int l, int c)
            : base(l, c)
        {
            Record = record;
            Name = name;
            Modifications = mods;
        }
    }

    public class RecProjExpr : Expression
    {
        public Expression Record { get; private set; }
        public string Name { get; private set; }
        public string Field { get; private set; }

        public RecProjExpr(Expression record, string name, string field, int l, int c)
            : base(l, c)
        {
            Record = record;
            Name = name;
            Field = field;
        }
    }

    public class RecordField : Expression
    {
        public AtomExpr Name { get; private set; }
        public Expression Contents { get; private set; }

        public RecordField(AtomExpr name, Expression contents, int l, int c)
            : base(l, c)
        {
            Name = name;
            Contents = contents;
        }
    }

    public class RecordDef
    {
        public string Name { get; private set; }
        public List<Tuple<string, Expression>> Fields { get; private set; }

        public RecordDef(string name, List<Tuple<string, Expression>> fields)
        {
            Name = name;
            Fields = fields;
        }
    }

    public class RecordStore
    {
        public Dictionary<string, List<Tuple<string, Expression>>> Records { get; private set; }

        public RecordStore()
        {
            Records = new Dictionary<string, List<Tuple<string, Expression>>>();
        }

        public void AddRecordDef(RecordDef def)
        {
            if (Records.ContainsKey(def.Name))
                throw new RecordException("A record with the name of '" + def.Name + "' has already been defined");
            Records.Add(def.Name, def.Fields);
        }

        public int IndexOfField(string record, string field)
        {
            if (!this.ContainsRecordField(record, field))
                return -1;

            List<Tuple<string, Expression>> d = Records[record];
            for (int i = 0; i < d.Count; i++)
                if (d[i].Item1 == field) return i;

            return -1;
        }

        public bool ContainsRecord(string name)
        {
            return Records.ContainsKey(name);
        }

        public bool ContainsRecordField(string record, string field)
        {
            if (!this.ContainsRecord(record))
                return false;

            for (int i = 0; i < Records[record].Count; i++)
                if (Records[record][i].Item1 == field) return true;

            return false;
        }
    }

    [Serializable]
    public class RecordException : Exception
    {
        public RecordException() { }
        public RecordException(string message) : base(message) { }
        public RecordException(string message, Exception inner) : base(message, inner) { }
        protected RecordException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context)
            : base(info, context) { }
    }
}
